<template>
  <div class="canvas-container">
    <CanvasToolbar
      v-model:snapToGrid="snapToGrid"
      v-model:showGrid="showGrid"
      @clear="handleClear"
      @undo="undo"
      @redo="redo"
      @zoomIn="zoomIn"
      @zoomOut="zoomOut"
      @fitView="fitView"
      ref="toolbar"
    />
    <div 
      ref="canvasRef"
      class="canvas" 
      :class="{ 'show-grid': showGrid }"
      @dragenter.prevent
      @dragover.prevent
      @dragleave.prevent
      @drop="onDrop"
      @click="handleCanvasClick"
      @mouseleave="handleCanvasLeave"
    >
      <!-- 网格背景 -->
      <div class="grid-background"></div>
      
      <!-- 节点 -->
      <div
        v-for="node in nodes"
        :key="node.id"
        :id="node.id"
        class="flowchart-node"
        :class="{ 'selected': selectedNode === node }"
        :style="nodeStyle(node)"
        @click.stop="handleNodeClick(node)"
        @dblclick.stop="openConfigPanel(node)"
        @contextmenu.prevent="showContextMenu($event, node)"
      >
        <el-icon><component :is="node.data.icon"/></el-icon>
        <span>{{ node.data.name }}</span>
      </div>
    </div>
    
    <!-- 右键菜单 -->
    <div v-show="contextMenu.visible" 
      class="context-menu"
      :style="{
        left: `${contextMenu.x}px`,
        top: `${contextMenu.y}px`
      }"
    >
      <div class="menu-item" @click="deleteSelectedNode">
        <el-icon><Delete /></el-icon>
        <span>删除节点</span>
      </div>
    </div>
    
    <!-- 配置面板 -->
    <el-drawer
      v-model="configDrawer.visible"
      :title="configDrawer.title"
      size="30%"
    >
      <ComponentConfig 
        v-if="configDrawer.visible"
        :component="configDrawer.component"
        @save="saveConfig"
      />
    </el-drawer>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick, watch, computed } from 'vue'
import { jsPlumb } from 'jsplumb'
import ComponentConfig from './ComponentConfig.vue'
import CanvasToolbar from './CanvasToolbar.vue'
import { useComponentStore } from '../stores/component'
import { useHistoryStore } from '../stores/history'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Delete } from '@element-plus/icons-vue'

const canvasRef = ref(null)
const nodes = ref([])
const connections = ref([])
const jsPlumbInstance = ref(null)
const toolbar = ref(null)
const selectedNode = ref(null)
const zoom = ref(1)
const snapToGrid = ref(true)
const showGrid = ref(true)
const componentStore = useComponentStore()
const historyStore = useHistoryStore()

const configDrawer = reactive({
  visible: false,
  title: '',
  component: null
})

// 右键菜单相关
const contextMenu = reactive({
  visible: false,
  x: 0,
  y: 0,
  node: null
})

const getJsPlumbConfig = (container) => ({
  container,
  // 连接线样式
  Connector: ['Flowchart', { cornerRadius: 5 }],
  // 端点样式
  Endpoint: ['Dot', { radius: 5 }],
  // 默认锚点配置
  Anchors: [['Left'], ['Right']],
  // 连接线样式
  PaintStyle: {
    strokeWidth: 2,
    stroke: '#409eff'
  },
  // 端点样式
  EndpointStyle: { 
    fill: '#409eff',
    radius: 5
  },
  // 禁止端点拖动
  EndpointHoverStyle: { fill: '#67c23a' },
  // 固定端点位置
  ConnectionsDetachable: false,
  // 禁止自连接
  LoopbackAllowed: false,
  // 设置缩放
  zoom: zoom.value,
  DragOptions: {
    cursor: 'move',
    grid: snapToGrid.value ? [20, 20] : null
  },
})

// 修改jsPlumb初始化函数
const initJsPlumb = () => {
  // 如果已有实例，先销毁
  if (jsPlumbInstance.value) {
    jsPlumbInstance.value.reset()
  } else {
    // 创建新实例
    jsPlumbInstance.value = jsPlumb.getInstance({
      Container: canvasRef.value,
      Connector: ['Flowchart', { cornerRadius: 5 }],
      Endpoint: ['Dot', { radius: 5 }],
      PaintStyle: { stroke: '#409eff', strokeWidth: 2 },
      EndpointStyle: { fill: '#409eff', radius: 5 },
      HoverPaintStyle: { stroke: '#67c23a' },
      EndpointHoverStyle: { fill: '#67c23a' },
      ConnectionsDetachable: false,
      LoopbackAllowed: false
    })
  }
  
  // 绑定事件
  bindJsPlumbEvents()
}

// 绑定jsPlumb事件
const bindJsPlumbEvents = () => {
  if (!jsPlumbInstance.value) return
  
  // 清除旧事件绑定
  jsPlumbInstance.value.unbind('connection')
  jsPlumbInstance.value.unbind('connectionDetached')
  
  // 连接创建
  jsPlumbInstance.value.bind('connection', (info) => {
    const sourceId = info.sourceId
    const targetId = info.targetId
    connections.value.push({ id: `${sourceId}-${targetId}`, source: sourceId, target: targetId })
    saveCurrentState()
  })
  
  // 连接删除
  jsPlumbInstance.value.bind('connectionDetached', (info) => {
    const sourceId = info.sourceId
    const targetId = info.targetId
    connections.value = connections.value.filter(conn => 
      conn.id !== `${sourceId}-${targetId}`
    )
    saveCurrentState()
  })
}

onMounted(() => {
  // 等待DOM更新后初始化
  nextTick(() => {
    initJsPlumb()
    
    // 为现有节点添加端点
    if (nodes.value.length > 0) {
      nodes.value.forEach(node => {
        const el = document.getElementById(node.id)
        if (el) {
          addNodeEndpoints(el)
        }
      })
    }
  })

  // 添加全局点击事件监听器
  document.addEventListener('click', closeContextMenu)
})

onUnmounted(() => {
  if (jsPlumbInstance.value) {
    jsPlumbInstance.value.destroy()
  }

  // 移除全局点击事件监听器
  document.removeEventListener('click', closeContextMenu)
})

// 将事件绑定逻辑抽取到单独的函数
const initJsPlumbEvents = () => {
  if (!jsPlumbInstance.value) return

  // 添加连接验证
  jsPlumbInstance.value.bind('beforeDrop', async (info) => {
    const sourceNode = nodes.value.find(n => n.id === info.sourceId)
    const targetNode = nodes.value.find(n => n.id === info.targetId)
    
    if (!sourceNode || !targetNode) return false
    
    // 使用本地验证替代服务器验证
    const isValid = componentStore.validateConnection(sourceNode.type, targetNode.type)
    
    if (!isValid) {
      ElMessage.warning(`${sourceNode.data.name} 不能连接到 ${targetNode.data.name}`)
    }
    
    return isValid
  })

  // 监听连接建立事件
  jsPlumbInstance.value.bind('connection', (info) => {
    const connection = info.connection
    const sourceId = connection.sourceId
    const targetId = connection.targetId
    
    // 保存连接信息
    connections.value.push({
      id: `${sourceId}-${targetId}`,
      source: sourceId,
      target: targetId
    })
    // 立即保存新增连接的状态
    saveCurrentState()
  })

  // 监听连接删除事件
  jsPlumbInstance.value.bind('connectionDetached', (info) => {
    const sourceId = info.sourceId
    const targetId = info.targetId
    const connectionId = `${sourceId}-${targetId}`
    
    // 从连接数组中移除
    connections.value = connections.value.filter(conn => conn.id !== connectionId)
    // 立即保存删除连接后的状态
    saveCurrentState()
  })
}

// 修改保存状态函数
const saveCurrentState = () => {
  // 确保保存时使用最新的位置信息
  nodes.value.forEach(node => {
    const el = document.getElementById(node.id)
    if (el) {
      const { left, top } = el.style
      node.position = {
        x: parseInt(left, 10),
        y: parseInt(top, 10)
      }
    }
  })
  
  const state = {
    nodes: JSON.parse(JSON.stringify(nodes.value)),
    connections: JSON.parse(JSON.stringify(connections.value))
  }
  historyStore.addState(state)
  
  nextTick(() => {
    toolbar.value?.setCanUndo(historyStore.canUndo)
    toolbar.value?.setCanRedo(historyStore.canRedo)
  })
}

// 重写onDrop函数
const onDrop = async (event) => {
  try {
    event.preventDefault()
    
    const data = event.dataTransfer.getData('application/json')
    if (!data) return
    
    const component = JSON.parse(data)
    
    // 计算放置位置
    const canvasRect = canvasRef.value.getBoundingClientRect()
    const x = event.clientX - canvasRect.left
    const y = event.clientY - canvasRect.top
    
    // 网格对齐
    const position = {
      x: Math.round(x / 20) * 20,
      y: Math.round(y / 20) * 20
    }
    
    // 创建唯一ID的新节点
    const newNode = {
      id: component.type + '_' + Date.now(), // 确保ID唯一
      type: component.type,
      position,
      data: {
        name: component.name,
        icon: component.icon,
        config: { ...component.config }
      }
    }
    
    nodes.value.push(newNode)
    
    // 等待DOM更新
    await nextTick()
    
    // 确保jsPlumb实例存在
    if (!jsPlumbInstance.value) {
      initJsPlumb()
    }
    
    const el = document.getElementById(newNode.id)
    if (el) {
      // 添加拖动和端点
      addNodeEndpoints(el)
    }
    
    saveCurrentState()
  } catch (error) {
    console.error('放置组件失败:', error)
    ElMessage.error('放置组件失败')
  }
}

// 创建新函数添加端点和拖动
const addNodeEndpoints = (el) => {
  if (!el || !jsPlumbInstance.value) return
  
  // 先确保没有重复端点
  jsPlumbInstance.value.removeAllEndpoints(el)
  
  // 添加端点
  jsPlumbInstance.value.addEndpoint(el, {
    anchor: 'Right',
    isSource: true,
    isTarget: false,
    maxConnections: -1,
    endpoint: ['Dot', { radius: 5 }],
    paintStyle: { fill: '#409eff' },
    hoverPaintStyle: { fill: '#67c23a' }
  })
  
  jsPlumbInstance.value.addEndpoint(el, {
    anchor: 'Left',
    isSource: false,
    isTarget: true,
    maxConnections: -1,
    endpoint: ['Dot', { radius: 5 }],
    paintStyle: { fill: '#409eff' },
    hoverPaintStyle: { fill: '#67c23a' }
  })
  
  // 添加拖动功能
  jsPlumbInstance.value.draggable(el, {
    grid: snapToGrid.value ? [20, 20] : [1, 1],
    stop: (event) => {
      const node = nodes.value.find(n => n.id === el.id)
      if (node) {
        node.position = {
          x: parseInt(el.style.left),
          y: parseInt(el.style.top)
        }
        saveCurrentState()
      }
    }
  })
  
  // 重绘
  jsPlumbInstance.value.repaintEverything()
}

// 重写删除节点函数
const deleteSelectedNode = () => {
  const nodeToDelete = contextMenu.node
  if (!nodeToDelete) return
  
  const nodeId = nodeToDelete.id
  const nodeEl = document.getElementById(nodeId)
  
  try {
    // 1. 删除此节点的所有连接
    connections.value = connections.value.filter(conn => 
      conn.source !== nodeId && conn.target !== nodeId
    )
    
    // 2. 从jsPlumb中删除节点和端点
    if (jsPlumbInstance.value && nodeEl) {
      jsPlumbInstance.value.removeAllEndpoints(nodeEl)
      jsPlumbInstance.value.remove(nodeId)
    }
    
    // 3. 从数组中移除节点
    nodes.value = nodes.value.filter(n => n.id !== nodeId)
  } catch (error) {
    console.error('删除节点出错:', error)
  }
  
  // 关闭右键菜单和配置面板
  contextMenu.visible = false
  if (selectedNode.value === nodeToDelete) {
    selectedNode.value = null
    configDrawer.visible = false
  }
  
  // 重绘
  jsPlumbInstance.value?.repaintEverything()
  
  // 保存状态
  saveCurrentState()
}

// 重写清空画布
const clearCanvas = (addToHistory = true) => {
  try {
    // 重置jsPlumb
    if (jsPlumbInstance.value) {
      jsPlumbInstance.value.reset()
      bindJsPlumbEvents() // 重新绑定事件
    }
    
    // 重置所有状态
    nodes.value = []
    connections.value = []
    selectedNode.value = null
    configDrawer.visible = false
    
    // 添加到历史记录
    if (addToHistory) {
      historyStore.addState({ nodes: [], connections: [] })
    }

    // 触发画布清空事件
    emit('canvasCleared')
  } catch (error) {
    console.error('清空画布失败:', error)
    ElMessage.error('清空画布失败')
  }
}

// 修改 CanvasToolbar 组件中的清空画布处理
const handleClear = () => {
  ElMessageBox.confirm('确定要清空画布吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    clearCanvas()
    ElMessage.success('画布已清空')
  })
}

const openConfigPanel = (node) => {
  configDrawer.component = node.data
  configDrawer.title = `配置 ${node.data.name}`
  configDrawer.visible = true
  selectNode(node)
}

const saveConfig = (config) => {
  const node = nodes.value.find(n => n.id === config.id)
  if (node) {
    node.data = { ...node.data, ...config }
  }
  configDrawer.visible = false
}

// 右键菜单相关
const showContextMenu = (event, node) => {
  event.preventDefault()
  contextMenu.visible = true
  contextMenu.x = event.clientX
  contextMenu.y = event.clientY
  contextMenu.node = node
  selectNode(node)
}

// 点击其他地方关闭右键菜单
const closeContextMenu = () => {
  contextMenu.visible = false
}

// 修改节点拖动相关
const initDraggable = (el) => {
  if (!el || !jsPlumbInstance.value) return
  
  jsPlumbInstance.value.draggable(el, {
    grid: snapToGrid.value ? [20, 20] : [1, 1],
    containment: true,
    drag: (e) => {
      const node = nodes.value.find(n => n.id === el.id)
      if (node) {
        const pos = e.pos || [0, 0]
        const x = pos[0]
        const y = pos[1]
        
        // 更新节点位置
        node.position = {
          x: Math.round(x / 20) * 20,
          y: Math.round(y / 20) * 20
        }
        
        // 直接更新 DOM 元素位置
        el.style.left = `${node.position.x}px`
        el.style.top = `${node.position.y}px`
        
        // 重新计算连接
        jsPlumbInstance.value.revalidate(el.id)
      }
    },
    stop: () => {
      // 保存最终位置
      const node = nodes.value.find(n => n.id === el.id)
      if (node) {
        const { left, top } = el.style
        node.position = {
          x: parseInt(left, 10),
          y: parseInt(top, 10)
        }
      }
      
      nextTick(() => {
        // 确保元素存在
        const element = document.getElementById(el.id)
        if (element) {
          jsPlumbInstance.value?.revalidate(element)
        }
        jsPlumbInstance.value?.repaintEverything()
        saveCurrentState()
      })
    }
  })
}

// 修改恢复状态的函数
const restoreState = (state) => {
  if (!state) return
  
  // 清除当前画布
  clearCanvas(false)
  
  // 恢复状态
  nodes.value = state.nodes
  connections.value = state.connections
  
  // 重新创建连接
  nextTick(() => {
    nodes.value.forEach(node => {
      const el = document.getElementById(node.id)
      if (el) {
        // 添加端点
        addEndpoints(el)
      }
    })
    
    // 重建连接
    connections.value.forEach(conn => {
      jsPlumbInstance.value.connect({
        source: conn.source,
        target: conn.target
      })
    })
  })
}

// 修改撤销/重做函数
const undo = () => {
  const previousState = historyStore.undo()
  if (previousState) {
    restoreState(previousState)
  }
}

const redo = () => {
  const nextState = historyStore.redo()
  if (nextState) {
    restoreState(nextState)
  }
}

// 缩放相关
const zoomIn = () => {
  zoom.value = Math.min(2, zoom.value + 0.1)
  nextTick(() => {
    jsPlumbInstance.value.setZoom(zoom.value)
  })
}

const zoomOut = () => {
  zoom.value = Math.max(0.5, zoom.value - 0.1)
  nextTick(() => {
    jsPlumbInstance.value.setZoom(zoom.value)
  })
}

const fitView = () => {
  zoom.value = 1
  nextTick(() => {
    jsPlumbInstance.value.setZoom(1)
  })
}

// 监听缩放变化
watch(zoom, () => {
  nextTick(() => {
    jsPlumbInstance.value?.repaintEverything()
  })
})

// 监听网格对齐变化
watch(snapToGrid, (newValue) => {
  if (jsPlumbInstance.value) {
    jsPlumbInstance.value.setDragGrid(newValue ? [20, 20] : [1, 1])
  }
})

// 节点选择
const selectNode = (node) => {
  selectedNode.value = node
}

// 修改节点样式
const nodeStyle = computed(() => (node) => ({
  position: 'absolute',
  left: `${node.position.x}px`,
  top: `${node.position.y}px`,
  minWidth: '120px',
  height: '40px',
  transform: 'none' // 防止浏览器优化导致位置重置
}))

// 修改节点样式
const flowchartNodeStyle = `
.flowchart-node {
  position: absolute;
  padding: 8px 16px;
  background: white;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: move;
  user-select: none;
  z-index: 1;
  min-width: 120px;
  height: 40px;
  box-shadow: 0 2px 4px rgba(0,0,0,.1);
  transition: border-color 0.3s, box-shadow 0.3s;
}

.flowchart-node:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,.1);
  border-color: #409eff;
}

.flowchart-node.selected {
  border-color: #409eff;
  box-shadow: 0 0 0 2px rgba(64,158,255,.2);
}

.flowchart-node .el-icon {
  font-size: 16px;
}

.flowchart-node span {
  font-size: 14px;
}

.flowchart-endpoint {
  z-index: 10;
  cursor: crosshair;
  position: absolute !important;
  width: 10px !important;
  height: 10px !important;
}

.jtk-endpoint {
  z-index: 10;
  position: absolute !important;
}

.jtk-connector {
  z-index: 9;
  pointer-events: none;
}

.jtk-endpoint-anchor {
  pointer-events: all;
}
`

// 修改节点点击处理
const handleNodeClick = (node) => {
  selectNode(node)
}

// 添加画布点击处理
const handleCanvasClick = (event) => {
  // 如果点击的是画布本身（而不是节点），取消选中
  if (event.target === canvasRef.value || event.target.classList.contains('grid-background')) {
    selectedNode.value = null
    configDrawer.visible = false
  }
}

// 添加鼠标移出画布处理
const handleCanvasLeave = (event) => {
  // 检查是否真的离开了画布区域（而不是移入了子元素）
  const relatedTarget = event.relatedTarget
  if (!canvasRef.value.contains(relatedTarget)) {
    // 如果不是移入配置面板，则取消选中
    if (!configDrawer.visible || !relatedTarget?.closest('.el-drawer')) {
      selectedNode.value = null
    }
  }
}

// 导出组件状态供父组件使用
defineExpose({
  nodes,
  connections
})

const emit = defineEmits(['canvasCleared'])
</script>

<style scoped>
.canvas-container {
  flex: 1;
  height: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
}

.canvas {
  width: 100%;
  flex: 1;
  background: #ffffff;
  position: relative;
  overflow: hidden;
  min-height: 400px;
}

.grid-background {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  background-size: 20px 20px;
  background-image: none;
}

.show-grid .grid-background {
  background-image: 
    linear-gradient(to right, #f0f0f0 1px, transparent 1px),
    linear-gradient(to bottom, #f0f0f0 1px, transparent 1px);
}

.flowchart-node {
  position: absolute;
  padding: 8px 16px;
  background: white;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: move;
  user-select: none;
  z-index: 1;
  min-width: 120px;
  height: 40px;
  box-shadow: 0 2px 4px rgba(0,0,0,.1);
  transition: border-color 0.3s, box-shadow 0.3s;
}

.flowchart-node:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,.1);
  border-color: #409eff;
}

.flowchart-node.selected {
  border-color: #409eff;
  box-shadow: 0 0 0 2px rgba(64,158,255,.2);
}

.flowchart-node .el-icon {
  font-size: 16px;
}

.flowchart-node span {
  font-size: 14px;
}

.context-menu {
  position: fixed;
  background: white;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
  z-index: 3000;
  padding: 5px 0;
}

.menu-item {
  padding: 8px 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  transition: background-color 0.3s;
  color: #606266;
  
  &:hover {
    background-color: #ecf5ff;
    color: #409eff;
  }
  
  .el-icon {
    font-size: 16px;
  }
}
</style> 